﻿// <copyright file="PuzzleView.cs" company="ThorIndustry">Copyright (c) ThorIndustry. All rights reserved.</copyright>

public partial class PuzzleView : View
{
    public UnityEngine.Material SolutionMaterial;
    public UnityEngine.GameObject ShapePrefab;
    public UnityEngine.GameObject SolutionShapePrefab;

    public MouseInputManager MouseInputManager;
    
    private IPuzzleService puzzleService;
    private Shape[] shapes;
    private SolutionShape backgroundShape;
    private Shape hintShape;

    private ICameraService cameraService;

    public bool HasEnded
    {
        get;
        set;
    }

    public PaletteDefinition CurrentPaletteDefinition
    {
        get
        {
            return this.ViewService.CurrentPaletteDefinition;
        }
    }

    public SolutionShape SolutionShape
    {
        get
        {
            return this.backgroundShape;
        }
    }

    public Shape[] Shapes
    {
        get
        {
            return this.shapes;
        }
    }

    public static SolutionShape GenerateSolutionShape(PuzzleSolutionShape puzzleSolutionShape, UnityEngine.Color color, UnityEngine.Transform parent, UnityEngine.GameObject prefab, float borderSize = 0.1f)
    {
        UnityEngine.GameObject solutionObject = UnityEngine.GameObject.Instantiate(prefab) as UnityEngine.GameObject;

        SolutionShape solutionShape = solutionObject.GetComponent<SolutionShape>();
        if (solutionShape == null)
        {
            solutionShape = solutionObject.AddComponent<SolutionShape>();
        }

        solutionShape.borderSize = borderSize;
        solutionShape.Color = color;
        solutionShape.PuzzleSolutionShape = puzzleSolutionShape;
        solutionShape.transform.parent = parent;

        solutionShape.Initialize();

        return solutionShape;
    }

    public static Shape GenerateShape(PuzzleShape puzzleShape, UnityEngine.Color color, UnityEngine.Transform parent, UnityEngine.GameObject prefab)
    {
        UnityEngine.GameObject shapeGameObject = UnityEngine.GameObject.Instantiate(prefab) as UnityEngine.GameObject;
        Shape shape = shapeGameObject.GetComponent<Shape>();
        if (shape == null)
        {
            shape = shapeGameObject.AddComponent<Shape>();
        }

        shape.ShapeColor = color;
        shape.PuzzleShape = puzzleShape;

        shape.transform.parent = parent;

        float flipRotation = puzzleShape.Flipped ? 180 : 0;
        shape.transform.localEulerAngles = new UnityEngine.Vector3(0, flipRotation, puzzleShape.CurrentRotation);

        shape.transform.localPosition = puzzleShape.CurrentPosition;

        shape.name = puzzleShape.Name;

        return shape;
    }

    public override void BackMenu()
    {
        base.BackMenu();

        // Change to out game view.
        this.ViewService.Activate(typeof(OutGameView));
    }
    
    public override void Hide()
    {
        base.Hide();

        this.MouseInputManager.Hide();

        // Destroy all shape prefab.
        for (int index = 0; index < this.shapes.Length; ++index)
        {
            UnityEngine.GameObject.Destroy(this.shapes[index].gameObject);
        }

        this.shapes = new Shape[0];

        if (this.backgroundShape != null)
        {
            UnityEngine.GameObject.Destroy(this.backgroundShape.gameObject);
            this.backgroundShape = null;
        }

        if (this.hintShape != null)
        {
            UnityEngine.GameObject.Destroy(this.hintShape.gameObject);
            this.hintShape = null;
        }
    }
    
    public override void Show(object[] parameters)
    {
        UnityEngine.Debug.Log("Puzzle view show.");

        base.Show(parameters);

        this.puzzleService = Services.GetService<IPuzzleService>();
        UnityEngine.Camera.main.backgroundColor = this.CurrentPaletteDefinition.BackgroundColor.Color;

        this.cameraService = Services.GetService<ICameraService>();

        // Generate all the shape around the outline.
        this.GenerateShapes();

        // Generate the outline.
        this.GenerateBackgroundShape();

        // Generate the hint (GUI?).
        // this.GenerateHintShape();

        // Check difficulty.
        if (true)
        {
            this.backgroundShape.enabled = true;
        }

        this.MouseInputManager.Show();

        this.HasEnded = false;
    }

    private void GenerateBackgroundShape()
    {
        // Create the shapes parent.
        this.backgroundShape = PuzzleView.GenerateSolutionShape(this.puzzleService.CurrentPuzzle.PuzzleSolutionShape, this.CurrentPaletteDefinition.HintColor.Color, this.transform, this.SolutionShapePrefab);
    }

    private void GenerateShapes()
    {
        this.shapes = new Shape[this.puzzleService.CurrentPuzzle.Shapes.Length];

        for (int index = 0; index < this.puzzleService.CurrentPuzzle.Shapes.Length; ++index)
        {
            UnityEngine.Color color = UnityEngine.Color.black;
            color = this.CurrentPaletteDefinition.ShapeColors[index % this.CurrentPaletteDefinition.ShapeColors.Length].Color;

            this.shapes[index] = PuzzleView.GenerateShape(this.puzzleService.CurrentPuzzle.Shapes[index], color, this.transform, this.ShapePrefab);
            this.shapes[index].SelectionIndex = index;

            this.shapes[index].Initialize();
        }
    }

    ////private void OnGUI()
    ////{
    ////    if (this.puzzleService != null &&
    ////        this.puzzleService.CurrentPuzzle != null)
    ////    {
    ////        if (this.puzzleService.CurrentPuzzle.CheckAgainstSolution())
    ////        {
    ////            UnityEngine.Color previousColor = UnityEngine.GUI.color;
    ////            UnityEngine.GUIStyle style = new UnityEngine.GUIStyle();
    ////            style.fontSize = 20;

    ////            UnityEngine.GUI.color = UnityEngine.Color.red;
    ////            UnityEngine.GUILayout.Label("YOU WIN!!!", style);

    ////            UnityEngine.GUI.color = previousColor;
    ////        }
    ////        else
    ////        {
    ////            for (int index = 0; index < this.puzzleService.CurrentPuzzle.Shapes.Length; ++index)
    ////            {
    ////                bool isIn = true;
    ////                for (int vertice = 0; vertice < this.puzzleService.CurrentPuzzle.Shapes[index].Vertices.Length; ++vertice)
    ////                {
    ////                    if (!this.puzzleService.CurrentPuzzle.SolutionShape.IsPointInShape(this.puzzleService.CurrentPuzzle.Shapes[index].WorldVertices[vertice]))
    ////                    {
    ////                        isIn = false;
    ////                    }
    ////                }

    ////                if (isIn)
    ////                {
    ////                    UnityEngine.GUILayout.Label("The Shape " + this.puzzleService.CurrentPuzzle.Shapes[index].Name + " is in the solution shape");
    ////                }
    ////            }
    ////        }
    ////    }
    ////}

    private void Start()
    {
        this.MouseInputManager.Initialize(this);
    }

    private void Update()
    {
        if (this.puzzleService == null)
        {
            return;
        }

        if (this.backgroundShape != null &&
            this.cameraService != null)
        {
            // We want to place the camera as the solution shape does not go out of the screen.
            float widthAtGround = this.backgroundShape.ShapeWidth;
            widthAtGround = UnityEngine.Mathf.Max(widthAtGround, 20);

            // As I am in an ortographic camera, the orthographic width is computed with this formulas.
            // orthograhic width = UnityUnitWidth / screenWidth * screenHeight/2
            float orthographicSizeFromHorizontal = widthAtGround / UnityEngine.Screen.width * UnityEngine.Screen.height / 2;
            float orthographicSizeFromVertical = ((this.backgroundShape.ShapeHeight) / 2) + 2;

            this.cameraService.SetOrthograhicSize(UnityEngine.Mathf.Max(orthographicSizeFromHorizontal, orthographicSizeFromVertical));
        }

        if (!this.HasEnded &&
            this.puzzleService.CurrentPuzzle.CheckAgainstSolution())
        {
            // Show the end menu.
            this.ShowMenu(typeof(EndGameMenu));

            this.HasEnded = true;
        }
    }
}
